from jili.core import keyword
from jili.core import moheengine as mh
from jili.price import tick
import uuid
import threading
import queue
import os

sourceid=os.getpid()
from mohe.core.obj import getobjinfo
from jili.tool.state import ismongo,isredis
import redis
import pickle
pool = redis.ConnectionPool(host='127.0.0.1')
r = redis.Redis(connection_pool=pool)
def setredis(key,value):
    if isredis:
        r.set(key, pickle.dumps(value))
def setredis_map(name,key,data):
    if isredis:
        r.hset(name, key, pickle.dumps(data))
def setredis_mapall(name,data):
    if isredis:
        #print(name,data)
        for k ,v in data.items():
            r.hset(name, k, pickle.dumps(v))
def getredis(key):
    if isredis:
        p=r.get(key)
        if p:
            return pickle.loads(p)
        else:
            return {}
    else:
        return {}
def getredis_map(name,key=""):
    if isredis:
        if key=="":
            p=r.hgetall(name)
            if p:
                ret={}
                for k,v in p.items():
                    k1=str(k,encoding="utf")
                    ret[k1]=pickle.loads(v)
                return ret
            else:
                return {}
        else:
            p=r.hget(name,key)
            if p:
                return pickle.loads(p)
            else:
                return {}
    else:
        return {}
class ctppos():
    __adatersubject="adater_ctp"
    __onadatersubject="adater_onctp"
    def __init__(self,brokerid,investid,iscalc=True,issave=True):
        #initflag:是否启用poscalc;是否使用delphindb；
        self.__timer = threading.Timer(1,self.__dealqryQueue)
        self.__timer.start()
        self.investorid=investid
        self.brokerid=brokerid
        self.userid=investid
        self.__RequestID=0
        self.__qryQueue= queue.Queue()
        self.__undoubleqryQueue=[]
        self.__qry_syncret={}
        self.TIMEOUT=30
        mh.subscribe(self.__onadapter,ctppos.__onadatersubject,investid)
        self.iscalc=iscalc#正常交易注册回报，注册行情计算头寸
        self.issave=issave
        self.pos={}
        self.orders={}  #orderid map all
        self.orderbook={}#orderid map  trdaing
        self.cashinbook={}
        self.fund=dict(
            avlfund=0
            ,avlfund0=0
            ,frozenfund=0
            ,margin=0
            ,asset=0
            ,pl=0
            ,pl_close=0
            ,pl_posbydate=0
        )
        self.issubtick=[]
        self.islogin=False
        self.prelastprice={}
        self.__setoncall={}
        self.__useroncall={}
        """
        ReqOrderInsert 
请求报单，对应于上一节中的第1步。  
OnRspOrderInsert 
综合交易平台交易核心返回的包含错误信息的报单响应，对应于上一节中的第7步的第1种情况。  
OnRtnOrder 
交易系统返回的报单状态，每次报单状态发生变化时被调用。一次报单过程中会被调用数次：交易系统将报单向交易所提交时（上述流程8中的第2个过程），交易所撤销或接受该报单时，该报单成交时。 
新增处理方式：报单在交易所端校验失败，被交易所拒绝后，CTP系统同样通过此接口返回报错信息；其中的OrderStatusMsg字段包含报错信息。  
OnErrRtnOrderInsert 
此接口仅在报单被CTP端拒绝时被调用用来进行报错。  
OnRtnTrade 
如果该报单由交易所进行了撮合成交，交易所再次返回该报单的状态（已成交）。并通过此函数返回该笔成交。 
报单成交之后，一个报单回报（OnRtnOrder）和一个成交回报（OnRtnTrade）会被发送到客户端，报单回报中报单的状态为“已成交”。但是仍然建议客户端将成交回报作为报单成交的标志，因为CTP的交易核心在收到OnRtnTrade之后才会更新该报单的状态。如果客户端通过报单回报来判断报单成交与否并立即平仓，有极小的概率会出现在平仓指令到达CTP交易核心时该报单的状态仍未更新，就会导致无法平仓。
        OrderStatus  0 全部成交  1 部分成交，订单还在交易所撮合队列中  3 未成交，订单还在交易所撮合队列中  5 已撤销  a 未知-订单已提交交易所，未从交易所收到确认信息
        """
        self.__sysoncall=dict(
            #OnErrRtnOrderInsert=self.__sysonorder,
            #OnErrRtnOrderAction=self.__sysonorder,
            OnRspQrySettlementInfoConfirm=self.__onsettlement,
            OnRtnOrder=self.__sysonorder,
            OnRspQryOrder=self.__sysonorder,
            OnRspQryTradingAccount=self.__sysonfund,
            OnRspQryInvestorPosition=self.__sysonpostion
            ,OnRtnFromBankToFutureByBank=self.__OnRtnFromBankToFutureByBank
            ,OnRtnFromBankToFutureByFuture=self.__OnRtnFromBankToFutureByBank
            ,OnRtnFromFutureToBankByBank=self.__OnRtnFromFutureToBankByBank
            ,OnRtnFromFutureToBankByFuture=self.__OnRtnFromFutureToBankByBank
        )
    def getsyncret(self):
        return self.__qry_syncret
    def __onadapter(self,msg):
        #print("__onadapter",msg)
        cmd=msg["2"]["cmd"]
        data=msg["2"]
        if cmd in self.__sysoncall.keys():
            self.__sysoncall[cmd](data)
        if cmd in self.__useroncall.keys():
            self.__useroncall[cmd](data)
        if self.__qry_syncret:
            if "RequestID" in data.keys():
                if data["RequestID"]==self.__qry_syncret["RequestID"]:
                    if "RspInfo" in data.keys():
                        if data["RspInfo"]:
                            self.__qry_syncret.update(data["RspInfo"])
                        else:
                            self.__qry_syncret["ErrorID"]=0
                        self.__qry_syncret["data"]=data["data"]
                        self.__qry_syncret["event"].set()
                    else:
                        self.__qry_syncret["ErrorID"]=0
                        self.__qry_syncret["data"]=data["data"]
                        self.__qry_syncret["event"].set()
        
    def __IncRequestID(self):
        """ 自增并返回请求ID """
        self.__RequestID += 1
        return self.__RequestID
    def login(self,password,p=""):
        self.islogin=False
        msg=dict(cmd="login",BrokerID=self.brokerid,InvestorID=self.investorid,Password=password,UserID=self.investorid,RequestID=self.__IncRequestID(),PID=sourceid)
        if p!="":
            msg["private"]=p
        self.__qry_syncret["event"]=threading.Event()
        self.__qry_syncret["RequestID"]=msg["RequestID"]
        self.__qry_syncret['event'].clear()
        rst = mh.safesend_sync(ctppos.__adatersubject,self.investorid,msg)
        if rst["errcode"]==0:
            if self.__qry_syncret['event'].wait(self.TIMEOUT):
                if self.__qry_syncret['ErrorID'] == 0:
                    self.__qrysettlement_imp()
                    self.__qrypositon_imp()
                    self.__qryfund_imp()
                    self.__qryorder_imp()
                    self.islogin=True
                    return True
                else:
                    return False
            else:
                return False
        else:
            return False
    def logout(self):
        msg=dict(cmd="logout",InvestorID=self.investorid,UserID=self.investorid,RequestID=self.__IncRequestID(),PID=sourceid)
        self.__qry_syncret["event"]=threading.Event()
        self.__qry_syncret["RequestID"]=msg["RequestID"]
        self.__qry_syncret['event'].clear()
        rst = mh.safesend_sync(ctppos.__adatersubject,self.investorid,msg)
        if rst["errcode"]==0:
            if self.__qry_syncret['event'].wait(self.TIMEOUT):
                if self.__qry_syncret['ErrorID'] == 0:
                    return True
                else:
                    return False
            else:
                return False
        else:
            return False
    def getorderid(self):
        return uuid.uuid1().urn
    def __onsettlement(self,data):
        #print(data)
        if data["cmd"]=="OnRspQrySettlementInfoConfirm":#查询是否确认结算单
            if data["data"]  is None:
                ReqSettlementInfoConfirm=dict( 
                    cmd='reqSettlementInfoConfirm'
                    ,ConfirmDate=''
                    ,ConfirmTime=''
                ) 
                self.timerqry(ReqSettlementInfoConfirm)
    def __qrypositon_imp(self,fresh=False):
        if fresh:
            req=dict( cmd='reqQryInvestorPosition')
            self.timerqry(req)
        else:
            key=keyword.ctp_pos+self.investorid
            ret=getredis_map(key)
            if ret:
                for v in ret.values():
                    self.__sysonpostion(v)
            else:
                req=dict( cmd='reqQryInvestorPosition')
                self.timerqry(req)
    def __qryfund_imp(self,fresh=True):
        if fresh:
            req=dict( cmd='reqQryTradingAccount')
            self.timerqry(req)
        else:
            key=keyword.ctp_fund+self.investorid
            ret=getredis(key)
            if ret:
                self.__sysonfund(ret)
            else:
                self.__isfundqry=False
                req=dict( cmd='reqQryTradingAccount')
                self.timerqry(req)
    def __qryorder_imp(self,fresh=False):
        if fresh:
            req=dict( cmd='reqQryOrder')
            self.timerqry(req)
        else:
            key=keyword.ctp_order+self.investorid
            ret=getredis_map(key)
            if ret:
                for v in ret.values():
                    self.__sysonorder(v)
            else:
                self.__isfundqry=False
                req=dict( cmd='reqQryOrder')
                self.timerqry(req)
    def __qrysettlement_imp(self,fresh=False):
        if fresh:
            req=dict( cmd='reqQrySettlementInfoConfirm')
            self.timerqry(req)
            req=dict( cmd='reqQrySettlementInfo')
            self.timerqry(req)
        else:
            key=keyword.ctp_settlement+self.investorid
            ret=getredis(key)
            if ret:
                    self.__onsettlement(ret)
            else:
                self.__isfundqry=False
                req=dict( cmd='reqQrySettlementInfoConfirm')
                self.timerqry(req)
            key=keyword.ctp_settlinfo+self.investorid
            ret=getredis(key)
            if not ret:
                req=dict( cmd='reqQrySettlementInfo')
                self.timerqry(req)
    def timerqry(self,req):
        if self.__qryQueue.empty():
            self.__qryQueue.put(req)
            self.__undoubleqryQueue.append(req["cmd"])
            if not self.__timer.isAlive():
                self.__dealqryQueue()
        else:
            if req["cmd"] not in self.__undoubleqryQueue:
                self.__qryQueue.put(req)
                self.__undoubleqryQueue.append(req["cmd"])
    def __dealqryQueue(self):
        if not self.__qryQueue.empty():
            req= self.__qryQueue.get()
            self.__undoubleqryQueue.remove(req["cmd"])
            #ppid=ctypes.CDLL('libc.so.6').syscall(186)
            #print("timer1:",ppid,req)
            self.qry(req,issync=False)
            #print("timer2:",ppid,req)
            self.__timer = threading.Timer(1,self.__dealqryQueue)
            self.__timer.start()
    def qry(self,req,issync=True,oncall=""):
        req["InvestorID"]=self.investorid
        if "RequestID" not in req.keys():
            req["RequestID"]=self.__IncRequestID()
        cmd="OnRsq"+req["cmd"][3:]
        ret={}
        a= False
        if oncall!="":
            self.__useroncall[cmd]=oncall
        #rst = mh.safesend_sync(ctppos.__adatersubject,self.investorid,req)
        if issync:
            self.__qry_syncret["event"]=threading.Event()
            self.__qry_syncret["RequestID"]=req["RequestID"]
            self.__qry_syncret['event'].clear()
        rst = mh.safesend_sync(ctppos.__adatersubject,self.investorid,req)
        if issync:
            if rst["errcode"]==0:
                if self.__qry_syncret['event'].wait(self.TIMEOUT):
                    #print(self.__qry_syncret)
                    if self.__qry_syncret['ErrorID'] == 0:
                        a= True
                        ret=self.__qry_syncret['data'] 
        else:
            if rst["errcode"]==0:
                a= True
        return req["RequestID"],a,ret
    def setonfund(self,oncall):  
        self.__setoncall["onfund"]=oncall
    def setonpos(self,oncall):  
        self.__setoncall["onposition"]=oncall
    def setonorder(self,oncall):  
        self.__setoncall["onorder"]=oncall
    def __onfund(self,msg):
        self.__savefund(msg)
        if "onfund" in self.__setoncall.keys():
            self.__setoncall["onfund"](msg)
    def __onposition(self,msg):
        #print(msg,islast)
        self.__savepos(msg)
        if "onposition" in self.__setoncall.keys():
            self.__setoncall["onposition"](msg)
    def __onorder(self,msg):
        self.__saveorder(msg)
        if "onorder" in self.__setoncall.keys():
            self.__setoncall["onorder"](msg)
    def BO(self,obj,qty,price):
        return self.submitorder(obj,"","0","0",qty,price)
    def BC(self,obj,qty,price):
        return self.submitorder(obj,"","0","1",qty,price)
    def SO(self,obj,qty,price):
        return self.submitorder(obj,"","1","0",qty,price)
    def SC(self,obj,qty,price):
        return self.submitorder(obj,"","1","1",qty,price)
    """
    def autobs(self,order):
    def sendorder_market(self,order):
    def sendorder_limit(self,order):
    def sendorder(self,order): 
    """
    def buy(self,obj,qty,price):
        if obj in self.pos.keys():
            pos=self.pos[obj]
            if pos["bs"]=="1":
                if pos["qty"]<qty:
                    self.BC(obj,pos["qty"],price)
                    sqty=qty-pos["qty"]
                    ret=self.BO(obj,sqty,price)
                else:
                    ret=self.BC(obj,qty,price)
            else:
                ret=self.BO(obj,qty,price)
        else:
            ret=self.BO(obj,qty,price)
        return ret
    def sell(self,obj,qty,price):
        if obj in self.pos.keys():
            pos=self.pos[obj]
            if pos["bs"]=="0":
                if pos["qty"]<qty:
                    self.SC(obj,pos["qty"],price)
                    sqty=qty-pos["qty"]
                    ret=self.SO(obj,sqty,price)
                else:
                    ret=self.SC(obj,qty,price)
            else:
                ret=self.SO(obj,qty,price)
        else:
            ret=self.SO(obj,qty,price)
        return ret
    def submitorder(self,obj,mkcode,bs,openclose,qty,price,orderid="",issync=True,oncall=""):
        if orderid=="":
            orderid=self.getorderid()
        ReqOrderInsert=dict( 
            cmd='reqOrderInsert'
            ,InstrumentID=obj
            ,Direction=bs
            ,CombOffsetFlag=openclose
            ,VolumeTotalOriginal=qty
            ,LimitPrice=price
            ,ExchangeID=mkcode
            ,RequestID=orderid
            ,MinVolume=1
            ,ContingentCondition="1"
            ,ForceCloseReason="0"
            ,orderid=orderid
        ) 
        ret = self.qry(ReqOrderInsert,issync=issync,oncall=oncall)
        return ret
    def cancelorder(self,orderid="",orderref="",issync=True,oncall=""):  
        if orderid!="":
            if orderid in self.orderbook.keys():
                order=self.orderbook[orderid]
                ReqOrderAction=dict( 
                    cmd='reqOrderAction'
                    ,OrderRef=order["OrderRef"]
                    ,FrontID=order["FrontID"]
                    ,SessionID=order["SessionID"]
                    ,InstrumentID=order["obj"]
                    ,ExchangeID=order["marketcode"]
                    ,ActionFlag='0'
                    ,RequestID=orderid
                    ,orderid=orderid
                ) 
        elif orderref!="":
            for orderid,order in self.orderbook.items():
                if orderref ==order["OrderRef"]:
                    ReqOrderAction=dict( 
                        cmd='reqOrderAction'
                        ,OrderRef=order["OrderRef"]
                        ,FrontID=order["FrontID"]
                        ,SessionID=order["SessionID"]
                        ,InstrumentID=order["obj"]
                        ,ExchangeID=order["marketcode"]
                        ,ActionFlag='0'
                        ,RequestID=orderid
                        ,orderid=orderid
                    ) 
                    break
        else:
            ReqOrderAction={}
        if ReqOrderAction:
            ret = self.qry(ReqOrderAction,issync=issync,oncall=oncall)
            return ret
        else:
            return ("",False,{})
    def __sysonfund(self,data):
        data=data["data"]
        self.__isfundqry=True
        if data is not None:
            self.fund["avlfund"]=data["Available"]
            if data["PositionProfit"]<0:
                self.fund["avlfund0"]=data["Available"]-data["PositionProfit"]
            else:
                self.fund["avlfund0"]=data["Available"]
            self.fund["margin"]=data["CurrMargin"]
            self.fund["frozenfund"]=data["FrozenCash"]+data["FrozenCommission"]
            self.fund["pl_close"]=data["CloseProfit"]
            self.fund["pl_posbydate"]=data["PositionProfit"]
            self.fund["pl"]=data["PositionProfit"]
            self.fund["asset"]=self.fund["avlfund"]+self.fund["margin"]+self.fund["frozenfund"]
            self.__onfund(self.fund)
    def __OnRtnFromBankToFutureByBank(self,data0):
        data=data0["data"]
        key = data["PlateSerial"]
        if data["ErrorID"]==0:
            if key not in self.cashinbook.keys():
                self.cashinbook[key]=dict(
                    AccountTitle='cashin'
                    ,amount=data["TradeAmount"]
                    ,timekey=data["TradeDate"]+" "+data["TradeTime"]
                )
                self.fund["avlfund"]=self.fund["avlfund"]+data['TradeAmount']
                self.fund["avlfund0"]=self.fund["avlfund0"]+data['TradeAmount']
                self.__onfund(self.fund)
    def __OnRtnFromFutureToBankByBank(self,data0):
        data=data0["data"]
        key = data["PlateSerial"]
        if data["ErrorID"]==0:
            if key not in self.cashinbook.keys():
                self.cashinbook[key]=dict(
                    AccountTitle='cashout'
                    ,amount=data["TradeAmount"]
                    ,timekey=data["TradeDate"]+" "+data["TradeTime"]
                )
                self.fund["avlfund"]=self.fund["avlfund"]-data['TradeAmount']
                self.fund["avlfund0"]=self.fund["avlfund0"]-data['TradeAmount']
                self.__onfund(self.fund)
    def reclacfund(self):
        pl=0
        pl_close=0
        pl_posbydate=0
        for pos in self.pos.values():
            pl=pl+pos["pl"]
            pl_close=pl_close+pos["pl_close"]
            pl_posbydate=pl_posbydate+pos["pl_posbydate"]
        self.fund["pl"]=pl
        self.fund["pl_close"]=pl_close
        self.fund["pl_posbydate"]=pl_posbydate
        if pl_posbydate < 0:
            self.fund["avlfund"]=self.fund["avlfund0"]+pl_posbydate
        else:
            self.fund["avlfund"]=self.fund["avlfund0"]
        self.__savefund(self.fund)
    def __savepos(self,pos):
        if self.issave:
            name=keyword.g_pos+self.investorid
            key=pos["key"]
            setredis_map(name,key,pos)
    def __savefund(self,msg):
        if self.issave:
            key=keyword.g_fund+self.investorid
            setredis(key,msg)
    def __saveorder(self,msg):
        if self.issave:
            name=keyword.g_order+self.investorid
            key=msg["orderid"]
            setredis_map(name,key,msg)
    def __ontick(self,t):
        obj=t["obj"]
        lastprice=t["LastPrice"]
        presettprice=t["PreSettlementPrice"]
        reclac=False
        if obj in self.prelastprice.keys():
            if lastprice!=self.prelastprice[obj]:
                self.prelastprice[obj]=lastprice
                key = obj+"."+"b"#PyCTP.THOST_FTDC_PD_Long
                if ismongo:
                    objinfo=getobjinfo(obj)
                else:
                    objinfo=dict(size=0)
                if key in self.pos.keys():
                    pos0=self.pos[key]
                    pos0["pl"]=(lastprice-pos0["opencost"])*pos0["qty"]*objinfo["size"]
                    pos0["pl_close"]=pos0["pl"]-pos0["fee"]
                    pos0["pl_posbydate"]=(lastprice-presettprice)*pos0["qty"]*objinfo["size"]
                    reclac=True
                    self.pos[key]=pos0
                key = obj+"."+"s"#PyCTP.THOST_FTDC_PD_Short
                if key in self.pos.keys():
                    pos0=self.pos[key]
                    pos0["pl"]=(pos0["opencost"]-lastprice)*pos0["qty"]*objinfo["size"]
                    pos0["pl_close"]=pos0["pl"]-pos0["fee"]
                    pos0["pl_posbydate"]=(presettprice-lastprice)*pos0["qty"]*objinfo["size"]
                    reclac=True
                    self.pos[key]=pos0
                if reclac:
                    self.__savepos(pos0)
                    self.reclacfund()
        else:
            self.prelastprice[obj]=lastprice
            key = obj+"."+"b"#PyCTP.THOST_FTDC_PD_Long
            if key in self.pos.keys():
                pos0=self.pos[key]
                pos0["pl"]=(lastprice-pos0["opencost"])*pos0["qty"]
                pos0["pl_close"]=pos0["pl"]-pos0["fee"]
                pos0["pl_posbydate"]=(lastprice-presettprice)*pos0["qty"]
                reclac=True
                self.pos[key]=pos0
            key = obj+"."+"s"#PyCTP.THOST_FTDC_PD_Short
            if key in self.pos.keys():
                pos0=self.pos[key]
                pos0["pl"]=(pos0["opencost"]-lastprice)*pos0["qty"]
                pos0["pl_close"]=pos0["pl"]-pos0["fee"]
                pos0["pl_posbydate"]=(presettprice-lastprice)*pos0["qty"]
                reclac=True
                self.pos[key]=pos0
            if reclac:
                self.reclacfund()

    def __sysonpostion(self,data):
        data=data["data"]
        if data is not None:
            if data["Position"]!=0:
                pos={}
                obj=data["InstrumentID"]
                pos["obj"]=obj
                #print("type PosiDirection:",type(data["PosiDirection"]))
                if data["PosiDirection"] in [2,"2"]:
                    pos["bs"]="b"
                elif data["PosiDirection"] in [3,"3"]:
                    pos["bs"]="s"
                else:
                    pos["bs"]="0"
                #pos["bs"]=data["PosiDirection"] #1:净；2:多头3：空头
                pos["qty"]=data["Position"]
                pos["ydqty"]=data["Position"]-data["Position"]
                pos["todayqty"]=data["Position"]
                pos["frozenqty"]=data["LongFrozen"]+data["ShortFrozen"]
                if ismongo:
                    objinfo=getobjinfo(obj)
                else:
                    objinfo=dict(size=0)
                pos["opencost"]=data["OpenCost"]/objinfo["size"]
                pos["usemargin"]=data["UseMargin"]
                pos["pl"]=data["PositionProfit"]
                pos["fee"]=2*data["Commission"]
                pos["pl_close"]=data["PositionProfit"]+pos["fee"]
                pos["pl_posbydate"]=data["PositionProfit"]
                #pos["islast"]=islast
                key = pos["obj"]+"."+pos["bs"]
                pos["key"]=key
                self.pos[key]=pos
                self.__onposition(pos)
                if self.iscalc:
                    if obj not in self.issubtick:
                        tick.subtick(obj,ontick=self.__ontick)
                        self.issubtick.append(obj)
    def __sysonorder(self,data0):
        cmd=data0["cmd"]
        data=data0["data"]
        #print("__sysonsubmit data:",data)
        if data:
            """
            #OnErrRtnOrderInsert=self.__sysonorder,
            #OnErrRtnOrderAction=self.__sysonorder,
            OnRtnOrder=self.__sysonorder,
            OnRspQryOrder=self.__sysonorder,
            OrderStatus  0 全部成交  1 部分成交，订单还在交易所撮合队列中  3 未成交，订单还在交易所撮合队列中  5 已撤销  a 未知-订单已提交交易所，未从交易所收到确认信息
            ///全部成交
            #define THOST_FTDC_OST_AllTraded '0'
            ///部分成交还在队列中
            #define THOST_FTDC_OST_PartTradedQueueing '1'
            ///部分成交不在队列中
            #define THOST_FTDC_OST_PartTradedNotQueueing '2'
            ///未成交还在队列中
            #define THOST_FTDC_OST_NoTradeQueueing '3'
            ///未成交不在队列中
            #define THOST_FTDC_OST_NoTradeNotQueueing '4'
            ///撤单
            #define THOST_FTDC_OST_Canceled '5'
            ///未知
            #define THOST_FTDC_OST_Unknown 'a'
            ///尚未触发
            #define THOST_FTDC_OST_NotTouched 'b'
            ///已触发
            #define THOST_FTDC_OST_Touched 'c'

            typedef char TThostFtdcOrderStatusType;

                        OrderSubmitStatus:
                        ///已经提交
            #define THOST_FTDC_OSS_InsertSubmitted '0'
            ///撤单已经提交
            #define THOST_FTDC_OSS_CancelSubmitted '1'
            ///修改已经提交
            #define THOST_FTDC_OSS_ModifySubmitted '2'
            ///已经接受
            #define THOST_FTDC_OSS_Accepted '3'
            ///报单已经被拒绝
            #define THOST_FTDC_OSS_InsertRejected '4'
            ///撤单已经被拒绝
            #define THOST_FTDC_OSS_CancelRejected '5'
            ///改单已经被拒绝
            #define THOST_FTDC_OSS_ModifyRejected '6'
            """
            orderid=data["orderid"]
            if orderid not in self.orders.keys():
                order={}
            else:
                order=self.orders[orderid]
            order["orderid"]=orderid
            order["obj"]=data["InstrumentID"]
            order["marketcode"]=data["ExchangeID"]
            order["bs"]=data["Direction"]
            order["openclose"]=data["CombOffsetFlag"]
            order["pricetype"]=data["OrderPriceType"]
            order["submitprice"]=data["LimitPrice"]
            order["submitprice"]=data["LimitPrice"]
            order["submitqty"]=data["VolumeTotalOriginal"]
            order["submitamount"]=order["submitprice"]*order["submitqty"]
            order["submittime"]=data["InsertTime"]
            order["cancelqty"]=data["VolumeTotalOriginal"]-data["VolumeTotal"]-data["VolumeTraded"]
            order["canceltime"]=data["CancelTime"]
            order["excprice"]=0
            order["excqty"]=data["VolumeTraded"]
            order["excamount"]=0
            order["exctime"]=""
            order["status"]=data["OrderStatus"]
            order["statusmsg"]=data["StatusMsg"]
            bookqty=data["VolumeTotal"]
            order["bookqty"]=bookqty
            order["ordersysid"]=data["OrderSysID"]
            order["OrderRef"]=data["OrderRef"]
            order["FrontID"]=data["FrontID"]
            order["SessionID"]=data["SessionID"]
            if order["status"] in ["1","3"]:#挂单
                if orderid not in self.orderbook.keys():
                    self.orderbook[orderid]=order
            elif order["status"] in ["0","2","4","5"]:
                if self.islogin:
                    self.__qrypositon_imp(fresh=True)
                    self.__qryfund_imp(fresh=True)
                if orderid in self.orderbook.keys():
                    del self.orderbook[orderid]
            self.orders[orderid]=order            
            self.__onorder(order)
class ctp_qry():
    __adatersubject="adater_ctp"
    __onadatersubject="adater_onctp"
    
    def __init__(self,brokerid,investid):
        self.investorid=investid
        self.brokerid=brokerid
        self.userid=investid
        self.__sysoncall={}
        self.__RequestID=0
        self.__qry_syncret={}
        self.TIMEOUT=30
        mh.subscribe(self.__onctp,ctp_qry.__onadatersubject,investid)
    def __onctp(self,msg):
        #print("__onrtn",msg)
        cmd=msg["2"]["cmd"]
        data=msg["2"]
        if cmd in self.__sysoncall.keys():
            self.__sysoncall[cmd](data)
        if data["RequestID"]==self.__qry_syncret["RequestID"]:
            #print("onsync:",data)
            if data["RspInfo"]:
                self.__qry_syncret.update(data["RspInfo"])
            else:
                self.__qry_syncret["ErrorID"]=0
            self.__qry_syncret["data"]=data["data"]
            self.__qry_syncret["event"].set()
    def __IncRequestID(self):
        """ 自增并返回请求ID """
        self.__RequestID += 1
        return self.__RequestID
    def login(self,password,p=""):
        msg=dict(cmd="login",BrokerID=self.brokerid,InvestorID=self.investorid,Password=password,UserID=self.investorid,RequestID=self.__IncRequestID())
        if p!="":
            msg["private"]=p
        self.__qry_syncret["event"]=threading.Event()
        self.__qry_syncret["RequestID"]=msg["RequestID"]
        self.__qry_syncret['event'].clear()
        rst = mh.safesend_sync(ctp_qry.__adatersubject,self.investorid,msg)
        if rst["errcode"]==0:
            if self.__qry_syncret['event'].wait(self.TIMEOUT):
                if self.__qry_syncret['ErrorID'] == 0:
                    return True
                else:
                    return False
            else:
                return False
        else:
            return False
    def logout(self):
        msg=dict(cmd="logout",InvestorID=self.investorid,UserID=self.investorid,RequestID=self.__IncRequestID())
        self.__qry_syncret["event"]=threading.Event()
        self.__qry_syncret["RequestID"]=msg["RequestID"]
        self.__qry_syncret['event'].clear()
        rst = mh.safesend_sync(ctp_qry.__adatersubject,self.investorid,msg)
        if rst["errcode"]==0:
            if self.__qry_syncret['event'].wait(self.TIMEOUT):
                if self.__qry_syncret['ErrorID'] == 0:
                    return True
                else:
                    return False
            else:
                return False
        else:
            return False
    def qry(self,req,issync=True,oncall=""):
        req["InvestorID"]=self.investorid
        if "RequestID" not in req.keys():
            req["RequestID"]=self.__IncRequestID()
        cmd="OnRsq"+req["cmd"][3:]
        ret={}
        if oncall!="":
            self.__sysoncall[cmd]=oncall
        if issync:
            self.__qry_syncret["event"]=threading.Event()
            self.__qry_syncret["RequestID"]=req["RequestID"]
            self.__qry_syncret['event'].clear()
        rst = mh.safesend_sync(ctp_qry.__adatersubject,self.investorid,req)
        if issync:
            if rst["errcode"]==0:
                if self.__qry_syncret['event'].wait(self.TIMEOUT):
                    #print(self.__qry_syncret)
                    if self.__qry_syncret['ErrorID'] == 0:
                        a= True
                        #if "data" in self.__qry_syncret.keys():
                        ret=self.__qry_syncret['data'] 
                    else:
                        a= False
                else:
                    a= False
            else:
                a= False
        else:
            if rst["errcode"]==0:
                a= True
            else:
                a= False
        return req["RequestID"],a,ret
